﻿using System;
using Mbs.Messaging;
using NUnit.Framework;
using Mbs.Messaging.Imp;

namespace MBTest
{
    [TestFixture]
    public class PersonHookTest
    {
        static MessageBus Actor;

        [SetUp]
        public virtual void Setup()
        {
            var repo = new MessageRepository();
            Actor = new MessageBus(repo);
            repo.ListnerManager.Register(new ChatHook(), new EatHook(), new WorkHook());

            //Actor.Subject<ChatMessage>(Topics.Chat).Subscriber.SubscribeFilter((s, e) =>
            Actor.SubscribeFilter<ChatMessage>(Topics.Chat,(s,e)=>
            {
                var msg = e.Message.Message;
                if (object.ReferenceEquals(s, msg.Another))
                {
                    e.Ignored = true;
                    return;
                }
                if (!object.ReferenceEquals(msg.Another, e.Receiver))
                {
                    e.Ignored = true;
                }

            });

            //Actor.Subject<EatMessage>(Topics.Eat).Subscriber.SubscribeFilter((s, e) =>
            Actor.SubscribeFilter<EatHook>(Topics.Eat,(s,e)=>
            {
                if (!object.ReferenceEquals(s, e.Receiver))
                    e.Ignored = true;
            });

            //Actor.Subject<WorkMessage>(Topics.Work).Subscriber.SubscribeFilter((s, e) =>
            Actor.SubscribeFilter<WorkMessage>(Topics.Work, (s, e) =>
            {
                if (!object.ReferenceEquals(s, e.Receiver))
                    e.Ignored = true;
            });
        }

        private class ChatHook : MessageListner
        {
            public ChatHook()
            {
                Type = MessageListnerType.Receiving;
            }

            public override void OnReceiving(object sender, ReceivingEventArgs e)
            {
                Topic<ChatMessage> msg =  e.Message as Topic<ChatMessage>;
                if (msg == null)
                    return;
                if (object.ReferenceEquals(sender, msg.Message.Another))
                {
                    e.Ignored = true;
                    return;
                }
                if (!object.ReferenceEquals(msg.Message.Another, e.Receiver))
                {
                    e.Ignored = true;
                }
            }
        }

        private class EatHook : MessageListner
        {
            public EatHook()
            {
                Type = MessageListnerType.Receiving;
            }

            public override void OnReceiving(object sender, ReceivingEventArgs e)
            {
                Topic<EatMessage> msg = e.Message as Topic<EatMessage>;
                if (msg == null)
                    return;
                if (!object.ReferenceEquals(sender, e.Receiver))
                {
                    e.Ignored = true;
                    return;
                }
            }
        }

        private class WorkHook : MessageListner
        {
            public WorkHook()
            {
                Type = MessageListnerType.Receiving;
            }

            public override void OnReceiving(object sender, ReceivingEventArgs e)
            {
                Topic<WorkMessage> msg = e.Message as Topic<WorkMessage>;
                if (msg == null)
                    return;
                if (!object.ReferenceEquals(sender, e.Receiver))
                {
                    e.Ignored = true;
                    return;
                }
            }
        }

        class Topics
        {
            public const string Chat = "Chat";
            public const string Eat = "Eat";
            public const string Work = "Work";
        }

        class Person:IPersonMessageHandler
        {
            

            public string Name { get; set; }
            public IDisposable Unsubscriber { get; private set; }

            public Person()
            {
                Unsubscriber = Actor.Subscribe<ChatMessage, EatMessage, WorkMessage>(
                    Topics.Chat, (s, e) =>
                    {
                        var sender = s as Person;
                        Console.WriteLine(string.Format("[{0}] 正在和[{1}] 谈论[{2}].", sender.Name, e.Message.Another.Name, e.Message.Topic));

                        const string exitContent = "烦不烦，天天讨论天气,拜拜！！！！";
                        if (e.Message.Topic.Content == exitContent)
                            Actor.Remove<ChatMessage>(Topics.Chat);
                        else
                            Chat(sender, new Topic { Name = e.Message.Topic.Name, Content = exitContent });
                    },
                    Topics.Eat, (s, e) =>
                    {
                        Console.WriteLine(string.Format("[{0}] 正在[{1}] 的 酒店就餐.", Name, e.Message.Restaurant.Address));
                    },
                    Topics.Work, (s, e) =>
                    {
                        Console.WriteLine(string.Format("[{0}] 正在为他的上级[{1}] 做[{2}].", Name, e.Message.ReportTo.Name,e.Message.Job.Name));
                    }
                    );
            }

            public void Chat(Person another, Topic topic)
            {
                Actor.Publish<ChatMessage>(Topics.Chat, this, new ChatMessage { Topic = topic, Another = another });
            }

            public void Eat(Restaurant restaurant)
            {
                Actor.Publish<EatMessage>(Topics.Eat, this, new EatMessage { Restaurant = restaurant });
            }

            public void Work(Person reportTo, Job job)
            {
                Actor.Publish<WorkMessage>(Topics.Work, this, new WorkMessage { Job = job, ReportTo = reportTo });
            }

            public override string ToString()
            {
                return Name;
            }
        }

        class Topic
        {
            public string Name;
            public string Content;
            public override string ToString()
            {
                return Name + " Content:" + Content;
            }
        }

        class ChatMessage
        {
            public Person Another;
            public Topic Topic;
        }

        class Restaurant { public string Address; }

        class EatMessage
        {
            public Restaurant Restaurant;
        }

        class Job
        {
            public string Name;
        }

        class WorkMessage
        {
            public Job Job;
            public Person ReportTo;
        }

        interface IPersonMessageHandler
        {
            void Chat(Person another, Topic topic);
            void Eat(Restaurant restaurant);
            void Work(Person reportTo, Job job);
        }

        [Test]
        public void Test()
        {
            var zhangSan = new Person { Name = "张三" };
            var liSi = new Person { Name = "李四" };
            var wangWu = new Person { Name = "王五" };

            zhangSan.Chat(liSi, new Topic { Name = "天气", Content = "今天天气也太热了，真受不了。。。。" });
            wangWu.Eat(new Restaurant { Address = "王府井大街" });

            liSi.Work(wangWu, new Job { Name = "客服" });

            zhangSan.Unsubscriber.Dispose();
            liSi.Unsubscriber.Dispose();
            wangWu.Unsubscriber.Dispose();
        }


    }
}
